/*
* JOALSoundImpl.java
* Copyright (C) 2004
*
* $Id: JOALSoundImpl.java,v 1.15 2005/12/04 19:21:04 cawe Exp $
*/
using System;
using Defines = Suake2.UI.Defines;
using Globals = Suake2.UI.Globals;
using Suake2.UI.game;
using Suake2.UI.qcommon;
using Suake2.UI.sound;
using Lib = Suake2.UI.util.Lib;
using Vargs = Suake2.UI.util.Vargs;
//UPGRADE_TODO: The package 'java.nio' could not be found. If it was not included in the conversion, there may be compiler issues. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1262'"
using java.nio;
//UPGRADE_TODO: The 'net.java.games.joal' package was found, but not necessarily converted. References to it may cause compile errors. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1280'"
using net.java.games.joal;
using EAX = net.java.games.joal.eax.EAX;
using EAXFactory = net.java.games.joal.eax.EAXFactory;
namespace Suake2.UI.sound.joal
{
	
	/// <summary> JOALSoundImpl</summary>
	public sealed class JOALSoundImpl : Sound
	{
		//UPGRADE_NOTE: Field 'EnclosingInstance' was added to class 'AnonymousClassxcommand_t' to access its enclosing instance. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1019'"
		private class AnonymousClassxcommand_t:xcommand_t
		{
			public AnonymousClassxcommand_t(JOALSoundImpl enclosingInstance)
			{
				InitBlock(enclosingInstance);
			}
			private void  InitBlock(JOALSoundImpl enclosingInstance)
			{
				this.enclosingInstance = enclosingInstance;
			}
			private JOALSoundImpl enclosingInstance;
			public JOALSoundImpl Enclosing_Instance
			{
				get
				{
					return enclosingInstance;
				}
				
			}
			public override void  execute()
			{
				Enclosing_Instance.Play();
			}
		}
		//UPGRADE_NOTE: Field 'EnclosingInstance' was added to class 'AnonymousClassxcommand_t1' to access its enclosing instance. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1019'"
		private class AnonymousClassxcommand_t1:xcommand_t
		{
			public AnonymousClassxcommand_t1(JOALSoundImpl enclosingInstance)
			{
				InitBlock(enclosingInstance);
			}
			private void  InitBlock(JOALSoundImpl enclosingInstance)
			{
				this.enclosingInstance = enclosingInstance;
			}
			private JOALSoundImpl enclosingInstance;
			public JOALSoundImpl Enclosing_Instance
			{
				get
				{
					return enclosingInstance;
				}
				
			}
			public override void  execute()
			{
				Enclosing_Instance.StopAllSounds();
			}
		}
		//UPGRADE_NOTE: Field 'EnclosingInstance' was added to class 'AnonymousClassxcommand_t2' to access its enclosing instance. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1019'"
		private class AnonymousClassxcommand_t2:xcommand_t
		{
			public AnonymousClassxcommand_t2(JOALSoundImpl enclosingInstance)
			{
				InitBlock(enclosingInstance);
			}
			private void  InitBlock(JOALSoundImpl enclosingInstance)
			{
				this.enclosingInstance = enclosingInstance;
			}
			private JOALSoundImpl enclosingInstance;
			public JOALSoundImpl Enclosing_Instance
			{
				get
				{
					return enclosingInstance;
				}
				
			}
			public override void  execute()
			{
				Enclosing_Instance.SoundList();
			}
		}
		//UPGRADE_NOTE: Field 'EnclosingInstance' was added to class 'AnonymousClassxcommand_t3' to access its enclosing instance. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1019'"
		private class AnonymousClassxcommand_t3:xcommand_t
		{
			public AnonymousClassxcommand_t3(JOALSoundImpl enclosingInstance)
			{
				InitBlock(enclosingInstance);
			}
			private void  InitBlock(JOALSoundImpl enclosingInstance)
			{
				this.enclosingInstance = enclosingInstance;
			}
			private JOALSoundImpl enclosingInstance;
			public JOALSoundImpl Enclosing_Instance
			{
				get
				{
					return enclosingInstance;
				}
				
			}
			public override void  execute()
			{
				Enclosing_Instance.SoundInfo_f();
			}
		}
		private void  InitBlock()
		{
			sfxDataBuffer = Lib.newByteBuffer(2 * 1024 * 1024);
			eaxEnv = Lib.newIntBuffer(1);
			streamBuffer = sfxDataBuffer.slice().order(ByteOrder.BIG_ENDIAN).asShortBuffer();
		}
		public System.String Name
		{
			/* (non-Javadoc)
			* @see jake2.sound.Sound#getName()
			*/
			
			get
			{
				return "joal";
			}
			
		}
		
		
		internal static AL al;
		internal static ALC alc;
		internal static EAX eax;
		
		internal cvar_t s_volume;
		
		private int[] buffers = new int[jake2.sound.Sound_Fields.MAX_SFX + jake2.sound.Sound_Fields.STREAM_QUEUE];
		
		// singleton 
		private JOALSoundImpl()
		{
			InitBlock();
		}
		
		/// <summary> unpack OpenAL shared library on Linux</summary>
		private void  unpack()
		{
			//UPGRADE_TODO: Method 'java.lang.System.getProperty' was converted to 'System.Environment.GetEnvironmentVariable' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javalangSystemgetProperty_javalangString'"
			System.String path = System.Environment.GetEnvironmentVariable("userprofile") + "/.jake2/libopenal.so";
			System.IO.FileInfo f = new System.IO.FileInfo(path);
			bool tmpBool;
			if (System.IO.File.Exists(f.FullName))
				tmpBool = true;
			else
				tmpBool = System.IO.Directory.Exists(f.FullName);
			if (!tmpBool)
			{
				try
				{
					SupportClass.FileSupport.CreateNewFile(f);
					//UPGRADE_ISSUE: Method 'java.lang.Class.getResourceAsStream' was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1000_javalangClassgetResourceAsStream_javalangString'"
					System.IO.Stream in_Renamed = GetType().getResourceAsStream("/libopenal.so");
					//UPGRADE_TODO: Constructor 'java.io.FileOutputStream.FileOutputStream' was converted to 'System.IO.FileStream.FileStream' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javaioFileOutputStreamFileOutputStream_javaioFile'"
					System.IO.Stream out_Renamed = new System.IO.FileStream(f.FullName, System.IO.FileMode.Create);
					sbyte[] buf = new sbyte[8192];
					int len;
					while ((len = SupportClass.ReadInput(in_Renamed, buf, 0, buf.Length)) > 0)
					{
						out_Renamed.Write(SupportClass.ToByteArray(buf), 0, len);
					}
				}
				catch (System.Exception e)
				{
					bool tmpBool2;
					if (System.IO.File.Exists(f.FullName))
					{
						System.IO.File.Delete(f.FullName);
						tmpBool2 = true;
					}
					else if (System.IO.Directory.Exists(f.FullName))
					{
						System.IO.Directory.Delete(f.FullName);
						tmpBool2 = true;
					}
					else
						tmpBool2 = false;
					bool generatedAux = tmpBool2;
				}
			}
		}
		
		/* (non-Javadoc)
		* @see jake2.sound.SoundImpl#Init()
		*/
		public bool Init()
		{
			
			// preload OpenAL native library
			//UPGRADE_TODO: Method 'java.lang.System.getProperty' was converted to 'System.Environment.GetEnvironmentVariable' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javalangSystemgetProperty_javalangString'"
			System.String os = System.Environment.GetEnvironmentVariable("OS");
			if (os.StartsWith("Linux"))
			{
				unpack();
			}
			else if (os.StartsWith("Windows"))
			{
				try
				{
					//UPGRADE_ISSUE: Method 'java.lang.System.loadLibrary' was not converted. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1000_javalangSystem'"
					System_Renamed.loadLibrary("OpenAL32");
				}
				//UPGRADE_NOTE: Exception 'java.lang.Throwable' was converted to 'System.Exception' which has different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1100'"
				catch (System.Exception e)
				{
				}
			}
			
			try
			{
				initOpenAL();
				al = ALFactory.getAL();
				checkError();
				initOpenALExtensions();
			}
			catch (OpenALException e)
			{
				//UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.getMessage' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
				Com.Printf(e.Message + '\n');
				return false;
			}
			//UPGRADE_NOTE: Exception 'java.lang.Throwable' was converted to 'System.Exception' which has different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1100'"
			catch (System.Exception e)
			{
				//UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.getMessage' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
				Com.DPrintf(e.Message + '\n');
				return false;
			}
			// set the master volume
			s_volume = Cvar.Get("s_volume", "0.7", Defines.CVAR_ARCHIVE);
			
			al.alGenBuffers(buffers.Length, buffers);
			int count = Channel.init(al, buffers);
			Com.Printf("... using " + count + " channels\n");
			al.alDistanceModel(net.java.games.joal.ALConstants_Fields.AL_INVERSE_DISTANCE_CLAMPED);
			Cmd.AddCommand("play", new AnonymousClassxcommand_t(this));
			Cmd.AddCommand("stopsound", new AnonymousClassxcommand_t1(this));
			Cmd.AddCommand("soundlist", new AnonymousClassxcommand_t2(this));
			Cmd.AddCommand("soundinfo", new AnonymousClassxcommand_t3(this));
			
			num_sfx = 0;
			
			Com.Printf("sound sampling rate: 44100Hz\n");
			
			StopAllSounds();
			Com.Printf("------------------------------------\n");
			return true;
		}
		
		
		private void  initOpenAL()
		{
			ALFactory.initialize();
			alc = ALFactory.getALC();
			System.String deviceName = null;
			
			//UPGRADE_TODO: Method 'java.lang.System.getProperty' was converted to 'System.Environment.GetEnvironmentVariable' which has a different behavior. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1073_javalangSystemgetProperty_javalangString'"
			System.String os = System.Environment.GetEnvironmentVariable("OS");
			if (os.StartsWith("Windows"))
			{
				deviceName = "DirectSound3D";
			}
			net.java.games.joal.Device device = alc.alcOpenDevice(deviceName);
			System.String deviceSpecifier = alc.alcGetString(device, net.java.games.joal.ALCConstants_Fields.ALC_DEVICE_SPECIFIER);
			System.String defaultSpecifier = alc.alcGetString(device, net.java.games.joal.ALCConstants_Fields.ALC_DEFAULT_DEVICE_SPECIFIER);
			
			Com.Printf(os + " using " + ((deviceName == null)?defaultSpecifier:deviceName) + '\n');
			
			net.java.games.joal.Context context = alc.alcCreateContext(device, new int[]{0});
			alc.alcMakeContextCurrent(context);
			// Check for an error.
			if (alc.alcGetError(device) != net.java.games.joal.ALCConstants_Fields.ALC_NO_ERROR)
			{
				Com.DPrintf("Error with SoundDevice");
			}
		}
		
		private void  initOpenALExtensions()
		{
			if (al.alIsExtensionPresent("EAX2.0"))
			{
				Com.Printf("... using EAX2.0\n");
				eax = EAXFactory.getEAX();
			}
			else
			{
				Com.Printf("... EAX2.0 not found\n");
				eax = null;
			}
		}
		
		internal void  exitOpenAL()
		{
			// Get the current context.
			net.java.games.joal.Context curContext = alc.alcGetCurrentContext();
			// Get the device used by that context.
			net.java.games.joal.Device curDevice = alc.alcGetContextsDevice(curContext);
			// Reset the current context to NULL.
			alc.alcMakeContextCurrent(null);
			// Release the context and the device.
			alc.alcDestroyContext(curContext);
			alc.alcCloseDevice(curDevice);
		}
		
		// TODO check the sfx direct buffer size
		// 2MB sfx buffer
		//UPGRADE_NOTE: The initialization of  'sfxDataBuffer' was moved to method 'InitBlock'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'"
		private ByteBuffer sfxDataBuffer;
		
		/* (non-Javadoc)
		* @see jake2.sound.SoundImpl#RegisterSound(jake2.sound.sfx_t)
		*/
		private void  initBuffer(sbyte[] samples, int bufferId, int freq)
		{
			ByteBuffer data = sfxDataBuffer.slice();
			data.put(samples).flip();
			al.alBufferData(buffers[bufferId], net.java.games.joal.ALConstants_Fields.AL_FORMAT_MONO16, data, data.limit(), freq);
		}
		
		private void  checkError()
		{
			Com.DPrintf("AL Error: " + alErrorString() + '\n');
		}
		
		private System.String alErrorString()
		{
			int error;
			System.String message = "";
			if ((error = al.alGetError()) != net.java.games.joal.ALConstants_Fields.AL_NO_ERROR)
			{
				switch (error)
				{
					
					case net.java.games.joal.ALConstants_Fields.AL_INVALID_OPERATION:  message = "invalid operation"; break;
					
					case net.java.games.joal.ALConstants_Fields.AL_INVALID_VALUE:  message = "invalid value"; break;
					
					case net.java.games.joal.ALConstants_Fields.AL_INVALID_ENUM:  message = "invalid enum"; break;
					
					case net.java.games.joal.ALConstants_Fields.AL_INVALID_NAME:  message = "invalid name"; break;
					
					default:  message = "" + error;
						break;
					
				}
			}
			return message;
		}
		
		/* (non-Javadoc)
		* @see jake2.sound.SoundImpl#Shutdown()
		*/
		public void  Shutdown()
		{
			StopAllSounds();
			Channel.shutdown();
			al.alDeleteBuffers(buffers.Length, buffers);
			exitOpenAL();
			
			Cmd.RemoveCommand("play");
			Cmd.RemoveCommand("stopsound");
			Cmd.RemoveCommand("soundlist");
			Cmd.RemoveCommand("soundinfo");
			
			// free all sounds
			for (int i = 0; i < num_sfx; i++)
			{
				if (known_sfx[i].name == null)
					continue;
				known_sfx[i].clear();
			}
			num_sfx = 0;
		}
		
		/* (non-Javadoc)
		* @see jake2.sound.SoundImpl#StartSound(float[], int, int, jake2.sound.sfx_t, float, float, float)
		*/
		public void  StartSound(float[] origin, int entnum, int entchannel, sfx_t sfx, float fvol, float attenuation, float timeofs)
		{
			
			if (sfx == null)
				return ;
			
			if (sfx.name[0] == '*')
				sfx = RegisterSexedSound(Globals.cl_entities[entnum].current, sfx.name);
			
			if (LoadSound(sfx) == null)
				return ; // can't load sound
			
			if (attenuation != Defines.ATTN_STATIC)
				attenuation *= 0.5f;
			
			PlaySound.allocate(origin, entnum, entchannel, buffers[sfx.bufferId], fvol, attenuation, timeofs);
		}
		
		private float[] listenerOrigin = new float[]{0, 0, 0};
		private float[] listenerOrientation = new float[]{0, 0, 0, 0, 0, 0};
		//UPGRADE_NOTE: The initialization of  'eaxEnv' was moved to method 'InitBlock'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'"
		private IntBuffer eaxEnv;
		private int currentEnv = - 1;
		private bool changeEnv = true;
		
		// TODO workaround for JOAL-bug
		// should be EAX.LISTENER
		private const int EAX_LISTENER = 0;
		// should be EAX.SOURCE
		private const int EAX_SOURCE = 1;
		
		/* (non-Javadoc)
		* @see jake2.sound.SoundImpl#Update(float[], float[], float[], float[])
		*/
		public void  Update(float[] origin, float[] forward, float[] right, float[] up)
		{
			Channel.convertVector(origin, listenerOrigin);
			al.alListenerfv(net.java.games.joal.ALConstants_Fields.AL_POSITION, listenerOrigin);
			
			Channel.convertOrientation(forward, up, listenerOrientation);
			al.alListenerfv(net.java.games.joal.ALConstants_Fields.AL_ORIENTATION, listenerOrientation);
			
			// set the listener (master) volume
			al.alListenerf(net.java.games.joal.ALConstants_Fields.AL_GAIN, s_volume.value_Renamed);
			
			if (eax != null)
			{
				// workaround for environment initialisation
				if (currentEnv == - 1)
				{
					eaxEnv.put(0, net.java.games.joal.eax.EAXConstants_Fields.EAX_ENVIRONMENT_UNDERWATER);
					eax.EAXSet(EAX_LISTENER, net.java.games.joal.eax.EAXConstants_Fields.DSPROPERTY_EAXLISTENER_ENVIRONMENT | net.java.games.joal.eax.EAXConstants_Fields.DSPROPERTY_EAXLISTENER_DEFERRED, 0, eaxEnv, 4);
					changeEnv = true;
				}
				
				if ((GameBase.gi.pointcontents.pointcontents(origin) & Defines.MASK_WATER) != 0)
				{
					changeEnv = currentEnv != net.java.games.joal.eax.EAXConstants_Fields.EAX_ENVIRONMENT_UNDERWATER;
					currentEnv = net.java.games.joal.eax.EAXConstants_Fields.EAX_ENVIRONMENT_UNDERWATER;
				}
				else
				{
					changeEnv = currentEnv != net.java.games.joal.eax.EAXConstants_Fields.EAX_ENVIRONMENT_GENERIC;
					currentEnv = net.java.games.joal.eax.EAXConstants_Fields.EAX_ENVIRONMENT_GENERIC;
				}
				if (changeEnv)
				{
					eaxEnv.put(0, currentEnv);
					eax.EAXSet(EAX_LISTENER, net.java.games.joal.eax.EAXConstants_Fields.DSPROPERTY_EAXLISTENER_ENVIRONMENT | net.java.games.joal.eax.EAXConstants_Fields.DSPROPERTY_EAXLISTENER_DEFERRED, 0, eaxEnv, 4);
				}
			}
			
			Channel.addLoopSounds();
			Channel.addPlaySounds();
			Channel.playAllSounds(listenerOrigin);
		}
		
		/* (non-Javadoc)
		* @see jake2.sound.SoundImpl#StopAllSounds()
		*/
		public void  StopAllSounds()
		{
			// mute the listener (master)
			al.alListenerf(net.java.games.joal.ALConstants_Fields.AL_GAIN, 0);
			PlaySound.reset();
			Channel.reset();
		}
		
		internal int s_registration_sequence;
		internal bool s_registering;
		
		/* (non-Javadoc)
		* @see jake2.sound.Sound#BeginRegistration()
		*/
		public void  BeginRegistration()
		{
			s_registration_sequence++;
			s_registering = true;
		}
		
		/* (non-Javadoc)
		* @see jake2.sound.Sound#RegisterSound(java.lang.String)
		*/
		public sfx_t RegisterSound(System.String name)
		{
			sfx_t sfx = FindName(name, true);
			sfx.registration_sequence = s_registration_sequence;
			
			if (!s_registering)
				LoadSound(sfx);
			
			return sfx;
		}
		
		/* (non-Javadoc)
		* @see jake2.sound.Sound#EndRegistration()
		*/
		public void  EndRegistration()
		{
			int i;
			sfx_t sfx;
			
			// free any sounds not from this registration sequence
			for (i = 0; i < num_sfx; i++)
			{
				sfx = known_sfx[i];
				if (sfx.name == null)
					continue;
				if (sfx.registration_sequence != s_registration_sequence)
				{
					// don't need this sound
					sfx.clear();
				}
			}
			
			// load everything in
			for (i = 0; i < num_sfx; i++)
			{
				sfx = known_sfx[i];
				if (sfx.name == null)
					continue;
				LoadSound(sfx);
			}
			
			s_registering = false;
		}
		
		internal sfx_t RegisterSexedSound(entity_state_t ent, System.String base_Renamed)
		{
			
			sfx_t sfx = null;
			
			// determine what model the client is using
			System.String model = null;
			int n = Globals.CS_PLAYERSKINS + ent.number - 1;
			if (Globals.cl.configstrings[n] != null)
			{
				int p = Globals.cl.configstrings[n].IndexOf('\\');
				if (p >= 0)
				{
					p++;
					model = Globals.cl.configstrings[n].Substring(p);
					//strcpy(model, p);
					p = model.IndexOf('/');
					if (p > 0)
						model = model.Substring(0, (p) - (0));
				}
			}
			// if we can't figure it out, they're male
			if (model == null || model.Length == 0)
				model = "male";
			
			// see if we already know of the model specific sound
			System.String sexedFilename = "#players/" + model + "/" + base_Renamed.Substring(1);
			//Com_sprintf (sexedFilename, sizeof(sexedFilename), "#players/%s/%s", model, base+1);
			sfx = FindName(sexedFilename, false);
			
			if (sfx != null)
				return sfx;
			
			//
			// fall back strategies
			//
			// not found , so see if it exists
			if (FS.FileLength(sexedFilename.Substring(1)) > 0)
			{
				// yes, register it
				return RegisterSound(sexedFilename);
			}
			// try it with the female sound in the pak0.pak
			if (model.ToUpper().Equals("female".ToUpper()))
			{
				System.String femaleFilename = "player/female/" + base_Renamed.Substring(1);
				if (FS.FileLength("sound/" + femaleFilename) > 0)
					return AliasName(sexedFilename, femaleFilename);
			}
			// no chance, revert to the male sound in the pak0.pak
			System.String maleFilename = "player/male/" + base_Renamed.Substring(1);
			return AliasName(sexedFilename, maleFilename);
		}
		
		internal static sfx_t[] known_sfx = new sfx_t[jake2.sound.Sound_Fields.MAX_SFX];
		internal static int num_sfx;
		
		internal sfx_t FindName(System.String name, bool create)
		{
			int i;
			sfx_t sfx = null;
			
			if (name == null)
				Com.Error(Defines.ERR_FATAL, "S_FindName: NULL\n");
			if (name.Length == 0)
				Com.Error(Defines.ERR_FATAL, "S_FindName: empty name\n");
			
			if (name.Length >= Defines.MAX_QPATH)
				Com.Error(Defines.ERR_FATAL, "Sound name too long: " + name);
			
			// see if already loaded
			for (i = 0; i < num_sfx; i++)
				if (name.Equals(known_sfx[i].name))
				{
					return known_sfx[i];
				}
			
			if (!create)
				return null;
			
			// find a free sfx
			for (i = 0; i < num_sfx; i++)
				if (known_sfx[i].name == null)
				// registration_sequence < s_registration_sequence)
					break;
			
			if (i == num_sfx)
			{
				if (num_sfx == jake2.sound.Sound_Fields.MAX_SFX)
					Com.Error(Defines.ERR_FATAL, "S_FindName: out of sfx_t");
				num_sfx++;
			}
			
			sfx = known_sfx[i];
			sfx.clear();
			sfx.name = name;
			sfx.registration_sequence = s_registration_sequence;
			sfx.bufferId = i;
			
			return sfx;
		}
		
		/*
		==================
		S_AliasName
		
		==================
		*/
		internal sfx_t AliasName(System.String aliasname, System.String truename)
		{
			sfx_t sfx = null;
			System.String s;
			int i;
			
			s = new System.Text.StringBuilder(truename).ToString();
			
			// find a free sfx
			for (i = 0; i < num_sfx; i++)
				if (known_sfx[i].name == null)
					break;
			
			if (i == num_sfx)
			{
				if (num_sfx == jake2.sound.Sound_Fields.MAX_SFX)
					Com.Error(Defines.ERR_FATAL, "S_FindName: out of sfx_t");
				num_sfx++;
			}
			
			sfx = known_sfx[i];
			sfx.clear();
			sfx.name = new System.Text.StringBuilder(aliasname).ToString();
			sfx.registration_sequence = s_registration_sequence;
			sfx.truename = s;
			// set the AL bufferId
			sfx.bufferId = i;
			
			return sfx;
		}
		
		/*
		==============
		S_LoadSound
		==============
		*/
		public sfxcache_t LoadSound(sfx_t s)
		{
			if (s.isCached)
				return s.cache;
			sfxcache_t sc = WaveLoader.LoadSound(s);
			if (sc != null)
			{
				initBuffer(sc.data, s.bufferId, sc.speed);
				s.isCached = true;
				// free samples for GC
				s.cache.data = null;
			}
			return sc;
		}
		
		/* (non-Javadoc)
		* @see jake2.sound.Sound#StartLocalSound(java.lang.String)
		*/
		public void  StartLocalSound(System.String sound)
		{
			sfx_t sfx = RegisterSound(sound);
			if (sfx == null)
			{
				Com.Printf("S_StartLocalSound: can't cache " + sound + "\n");
				return ;
			}
			StartSound(null, Globals.cl.playernum + 1, 0, sfx, 1, 1, 0.0f);
		}
		
		//UPGRADE_NOTE: The initialization of  'streamBuffer' was moved to method 'InitBlock'. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1005'"
		private ShortBuffer streamBuffer;
		
		/* (non-Javadoc)
		* @see jake2.sound.Sound#RawSamples(int, int, int, int, byte[])
		*/
		public void  RawSamples(int samples, int rate, int width, int channels, ByteBuffer data)
		{
			int format;
			if (channels == 2)
			{
				format = (width == 2)?net.java.games.joal.ALConstants_Fields.AL_FORMAT_STEREO16:net.java.games.joal.ALConstants_Fields.AL_FORMAT_STEREO8;
			}
			else
			{
				format = (width == 2)?net.java.games.joal.ALConstants_Fields.AL_FORMAT_MONO16:net.java.games.joal.ALConstants_Fields.AL_FORMAT_MONO8;
			}
			
			// convert to signed 16 bit samples
			if (format == net.java.games.joal.ALConstants_Fields.AL_FORMAT_MONO8)
			{
				ShortBuffer sampleData = streamBuffer;
				int value_Renamed;
				for (int i = 0; i < samples; i++)
				{
					value_Renamed = (data.get_Renamed(i) & 0xFF) - 128;
					sampleData.put(i, (short) value_Renamed);
				}
				format = net.java.games.joal.ALConstants_Fields.AL_FORMAT_MONO16;
				width = 2;
				data = sfxDataBuffer.slice();
			}
			
			Channel.updateStream(data, samples * channels * width, format, rate);
		}
		
		public void  disableStreaming()
		{
			Channel.disableStreaming();
		}
		
		/*
		===============================================================================
		
		console functions
		
		===============================================================================
		*/
		
		internal void  Play()
		{
			int i = 1;
			System.String name;
			while (i < Cmd.Argc())
			{
				name = new System.Text.StringBuilder(Cmd.Argv(i)).ToString();
				if (name.IndexOf('.') == - 1)
					name += ".wav";
				
				RegisterSound(name);
				StartLocalSound(name);
				i++;
			}
		}
		
		internal void  SoundList()
		{
			int i;
			sfx_t sfx;
			sfxcache_t sc;
			int size, total;
			
			total = 0;
			for (i = 0; i < num_sfx; i++)
			{
				sfx = known_sfx[i];
				if (sfx.registration_sequence == 0)
					continue;
				sc = sfx.cache;
				if (sc != null)
				{
					size = sc.length * sc.width * (sc.stereo + 1);
					total += size;
					if (sc.loopstart >= 0)
						Com.Printf("L");
					else
						Com.Printf(" ");
					Com.Printf("(%2db) %6i : %s\n", new Vargs(3).add(sc.width * 8).add(size).add(sfx.name));
				}
				else
				{
					if (sfx.name[0] == '*')
						Com.Printf("  placeholder : " + sfx.name + "\n");
					else
						Com.Printf("  not loaded  : " + sfx.name + "\n");
				}
			}
			Com.Printf("Total resident: " + total + "\n");
		}
		
		internal void  SoundInfo_f()
		{
			Com.Printf("%5d stereo\n", new Vargs(1).add(1));
			Com.Printf("%5d samples\n", new Vargs(1).add(22050));
			Com.Printf("%5d samplebits\n", new Vargs(1).add(16));
			Com.Printf("%5d speed\n", new Vargs(1).add(44100));
		}
		static JOALSoundImpl()
		{
			{
				S.register(new JOALSoundImpl());
			}
			{
				for (int i = 0; i < known_sfx.Length; i++)
					known_sfx[i] = new sfx_t();
			}
		}
	}
}